package com.y.report.entry;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.map.MapUtil;
import com.y.report.entity.ext.CurrJdbcExecOpt;
import com.y.report.hepler.DbHelper;
import com.y.report.util.DataPrinter;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.stream.Collectors;


/*
java -cp ext/report-api-1.0-SNAPSHOT.jar:ext/args4j-2.33.jar:ext/hutool-all-5.7.13.jar:ext/slf4j-api-1.7.30.jar:ext/logback-classic-1.2.5.jar:ext/logback-core-1.2.5.jar:ext/mysql-connector-java-5.1.34.jar \
com.y.report.entry.CurrJdbcExec \
--driver com.mysql.jdbc.Driver \
--url jdbc:mysql://10.192.147.3:9030/tpcds \
--username root --password root \
--total 10 --curr 2 \
--sql querys/doris_1t/sql_06.sql
 */
public class CurrJdbcExec {

    private static Logger log = LoggerFactory.getLogger(CurrJdbcExec.class);

    public static void main(String[] args) {
        final String dsKey = "defaultDataSource";

        CurrJdbcExecOpt argsOpt = new CurrJdbcExecOpt();
        CmdLineParser parser = new CmdLineParser(argsOpt);
        try {
            parser.parseArgument(args);
        } catch (CmdLineException e) {
            log.error(e.getMessage());
            parser.printUsage(System.err);
        }

        Map<String, String> props = new HashMap<>();
        props.put("driverClassName", argsOpt.getDriver());
        props.put("jdbcUrl", argsOpt.getUrl());
        props.put("username", argsOpt.getUsername());
        props.put("password", argsOpt.getPassword());
        props.put("maxActive", argsOpt.getCurr() + "");

        BiConsumer<Pair<Integer, Integer>, Map<String, Object>> open = (x, y) -> {
            DbHelper dbHelper = new DbHelper(props);
            y.put(dsKey, dbHelper);
            log.info("open");
        };

        BiConsumer<Pair<Integer, Integer>, Map<String, Object>> close = (x, y) -> {
            log.info("close");
        };

        BiFunction<Integer, Map<String, Object>, Object> call = (x, y) -> {
            List<String> sqls = Arrays.asList(argsOpt.getSql());
            List<Map<String, Object>> result = sqls.stream()
                    .map(sql -> {
                        if (FileUtil.isFile(sql))
                            return FileUtil.readUtf8String(sql);
                        return sql;
                    }).flatMap(sql -> {
                        DbHelper helper = MapUtil.get(y, dsKey, DbHelper.class);
                        List<Map<String, Object>> datas = Collections.emptyList();
                        try {
                            datas = helper.execSql(sql, Collections.emptyList(), false, true);
                        } catch (Exception e) {
                            log.error(e.getMessage());
                            e.printStackTrace();
                        }
                        return datas.stream();

                    }).collect(Collectors.toList());
            DataPrinter dataPrinter = new DataPrinter();
            if (argsOpt.getShowMode() == 2)
                dataPrinter.setLogOutputModel(DataPrinter.LogOutputModel.LOG);
            dataPrinter.print("title", result, 3);
            return null;
        };
        up(argsOpt.getTotal(), argsOpt.getCurr(), open, close, call);
    }

    private static void up(int total, int curr,
                           BiConsumer<Pair<Integer, Integer>, Map<String, Object>> open,
                           BiConsumer<Pair<Integer, Integer>, Map<String, Object>> close,
                           BiFunction<Integer, Map<String, Object>, Object> call) {
        ExecutorService pool = Executors.newFixedThreadPool(curr);
        Semaphore semaphore = new Semaphore(curr);
        HashMap<String, Object> globalMap = new HashMap<>(16);

        Pair<Integer, Integer> pair = Pair.of(total, curr);
        open.accept(pair, globalMap);
        try {
            for (int i = 0; i < total; i++) {
                semaphore.acquire();
                int finalI = i;
                log.debug("up call -> total:{}, curr:{}, currNum:{}", total, curr, finalI);
                pool.submit(() -> {
                    call.apply(finalI, globalMap);
                    semaphore.release();
                });
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
        } finally {
            pool.shutdown();
            log.info("up close ---------------------> total:{}, curr:{}", total, curr);
            close.accept(pair, globalMap);
        }
    }

}
